namespace Cik.Gapi4Net.Service.Impls
{
    using System;
    using System.Diagnostics;
    using System.Diagnostics.Contracts;
    using Contracts;
    using Core.AcsynRequest;
    using Core.Constant;
    using Core.Exceptions;
    using Core.Json;
    using Domain.Input;
    using Domain.Input.UrlBuilder;
    using Domain.Output.ImageSearch;
    using Entlib.Logging;
    using FluentValidation;
    using Microsoft.Practices.EnterpriseLibrary.Logging;

    internal class ImageSearchService : ServiceBase, IImageSearchService
    {
        private readonly IUrlBuilder<Image> _urlBuilder;
        private readonly IValidator<Image> _validator;

        public ImageSearchService()
        {
        }

        public ImageSearchService(ILoggerFactory loggerFactory, IDownloader downloader, IUrlBuilder<Image> urlBuilder, IValidator<Image> validator)
            : base(loggerFactory, downloader)
        {
            _urlBuilder = urlBuilder;
            _validator = validator;
        }

        public ImageSearchResult Search(Func<Image> func)
        {
            Contract.Assert(_downloader != null, "Downloader is null");
            Contract.Assert(_logger != null, "Logger is null");
            Contract.Assert(_urlBuilder != null, "UrlBuilder is null");
            Contract.Assert(_validator != null, "ImageValidator is null");

            try
            {
                // call the function for get the real entity
                var img = func();

                // validator this entity
                _validator.ValidateAndThrow(img);

                _urlBuilder.Entity = img;
                var result = _urlBuilder.BuildUrl();

                var searchUrl = CommonConstant.ImagesSearchUrl + result;

                return GetResultData<ImageSearchResult>(searchUrl);
            }
            catch (Exception ex)
            {
                var logEntry = new LogEntry(ex.Message, "GApi4Net", 1, 0, TraceEventType.Error, "GApi4Net", null);
                _logger.Write(logEntry);

                throw new ImageSearchException(ex.Message);
            }
        }

        public ImageSearchResult Search(string version, string query)
        {
            Contract.Assert(_downloader != null, "Downloader is null");
            Contract.Assert(_logger != null, "Logger is null");

            try
            {
                var webSearch = new Image { Version = version, Query = query };
                var searchUrl = CommonConstant.ImagesSearchUrl + webSearch.SearchWebUrl();

                _downloader.Add(searchUrl);
                _downloader.DownloadAll(x =>
                {
                    Result = x.Result;
                }).ExecuteAndWait();

                var webSearchResult = JsonHelper.DeserializeObject<ImageSearchResult>(Result);

                return webSearchResult;
            }
            catch (Exception ex)
            {
                var logEntry = new LogEntry(ex.Message, "GApi4Net", 1, 0, TraceEventType.Error, "GApi4Net", null);
                _logger.Write(logEntry);

                throw new ImageSearchException(ex.Message);
            }
        }
    }
}